// -*- C++ -*-
//=============================================================================
/**
 * @file    common.h
 *
 * Useful for preventing conflicts when using a third party library.
 *
 * @author HongNiu <hongniu@b5m.com>
 */
//=============================================================================

#ifndef _B5M_COMMON_COMMON_H_
#define _B5M_COMMON_COMMON_H_


//the below define and includes should be contained in config.h

#include <limits>
#include <assert.h>
#include <Windows.h>

#ifdef _UNICODE
	#define B5M_HAS_WCHAR
#endif

#define B5M_HAS_VERSIONED_NAMESPACE

#define B5M_USING_STATIC_B5M_OBJECT_MANAGER

//////////////////////////////////////////////////////////////////////////



//common macro define
#define B5M_COMMON_MAJOR_VERSION 0
#define B5M_COMMON_MINOR_VERSION 0
#define B5M_COMMON_BETA_VERSION 1

#if defined B5M_HAS_VERSIONED_NAMESPACE

	# ifndef B5M_VERSIONED_NAMESPACE_NAME
		# define B5M_MAKE_VERSIONED_NAMESPACE_NAME_IMPL(MAJOR,MINOR,BETA) B5M_ ## MAJOR ## _ ## MINOR ## _ ## BETA
		# define B5M_MAKE_VERSIONED_NAMESPACE_NAME(MAJOR,MINOR,BETA) B5M_MAKE_VERSIONED_NAMESPACE_NAME_IMPL(MAJOR,MINOR,BETA)
		# define B5M_VERSIONED_NAMESPACE_NAME B5M_MAKE_VERSIONED_NAMESPACE_NAME(B5M_COMMON_MAJOR_VERSION,B5M_COMMON_MINOR_VERSION,B5M_COMMON_BETA_VERSION)
	# endif  /* !B5M_VERSIONED_NAMESPACE_NAME */


	# define B5M_BEGIN_VERSIONED_NAMESPACE_DECL namespace B5M_VERSIONED_NAMESPACE_NAME {

	# define B5M_END_VERSIONED_NAMESPACE_DECL } \
		using namespace B5M_VERSIONED_NAMESPACE_NAME;

	#define BEGIN_B5M_NAMESPACE  namespace _b5m_common_ {
	#define END_B5M_NAMESPACE }

#else

	# define B5M_VERSIONED_NAMESPACE_NAME
	# define B5M_BEGIN_VERSIONED_NAMESPACE_DECL
	# define B5M_END_VERSIONED_NAMESPACE_DECL

#endif


#ifdef _DEBUG 
	#define   B5M_DEBUG
#else
	#define   B5M_DEBUG
#endif

//B5MExport
#define B5M_Export



// The number of bytes in a short.
# if !defined (B5M_SIZEOF_SHORT)
#   if (USHRT_MAX) == 255U
#     define B5M_SIZEOF_SHORT 1
#   elif (USHRT_MAX) == 65535U
#     define B5M_SIZEOF_SHORT 2
#   elif (USHRT_MAX) == 4294967295U
#     define B5M_SIZEOF_SHORT 4
#   elif (USHRT_MAX) == 18446744073709551615U
#     define B5M_SIZEOF_SHORT 8
#   else
#     error: unsupported short size, must be updated for this platform!
#   endif /* USHRT_MAX */
# endif /* !defined (B5M_SIZEOF_SHORT) */


// The number of bytes in an int.
# if !defined (B5M_SIZEOF_INT)
#   if (UINT_MAX) == 65535U
#     define B5M_SIZEOF_INT 2
#   elif (UINT_MAX) == 4294967295U
#     define B5M_SIZEOF_INT 4
#   elif (UINT_MAX) == 18446744073709551615U
#     define B5M_SIZEOF_INT 8
#   else
#     error: unsupported int size, must be updated for this platform!
#   endif /* UINT_MAX */
# endif /* !defined (B5M_SIZEOF_INT) */


// The number of bytes in a long.
# if !defined (B5M_SIZEOF_LONG)
#   if (ULONG_MAX) == 65535UL
#     define B5M_SIZEOF_LONG 2
#   elif ((ULONG_MAX) == 4294967295UL)
#     define B5M_SIZEOF_LONG 4
#   elif ((ULONG_MAX) == 18446744073709551615UL)
#     define B5M_SIZEOF_LONG 8
#   else
#     error: unsupported long size, must be updated for this platform!
#   endif /* ULONG_MAX */
# endif /* !defined (B5M_SIZEOF_LONG) */


// The number of bytes in a long long.
# if !defined (B5M_SIZEOF_LONG_LONG)
#   if defined (ULLONG_MAX)
#     if ((ULLONG_MAX) == 4294967295ULL)
#       define B5M_SIZEOF_LONG_LONG 4
#     elif ((ULLONG_MAX) == 18446744073709551615ULL)
#       define B5M_SIZEOF_LONG_LONG 8
#     endif
#   elif defined (ULONGLONG_MAX)
#     if ((ULONGLONG_MAX) == 4294967295ULL)
#       define B5M_SIZEOF_LONG_LONG 4
#     elif ((ULONGLONG_MAX) == 18446744073709551615ULL)
#       define B5M_SIZEOF_LONG_LONG 8
#     endif
#   endif
#   // If we can't determine the size of long long, assume it is 8
#   // instead of erroring out.  (Either ULLONG_MAX and ULONGLONG_MAX
#   // may not be supported; or an extended C/C++ dialect may need to
#   // be selected.  If this assumption is wrong, it can be addressed
#   // in the platform-specific config header.
#   if !defined (B5M_SIZEOF_LONG_LONG)
#     define B5M_SIZEOF_LONG_LONG 8
#   endif
# endif /* !defined (B5M_SIZEOF_LONG_LONG) */


B5M_BEGIN_VERSIONED_NAMESPACE_DECL

// The sizes of the commonly implemented types are now known.  Set up
// typedefs for whatever we can.  Some of these are needed for certain
// cases of B5M_UINT64, so do them before the 64-bit stuff.

/* defined (B5M_INT8_TYPE) */
typedef char  B5M_INT8; 

/* defined (B5M_UINT8_TYPE) */
typedef unsigned char   B5M_UINT8;
	

//#ifdef B5M_SIZEOF_SHORT == 2
	typedef short                 B5M_INT16;
// #elif B5M_SIZEOF_INT == 2
// 	typedef int                   B5M_INT16;
// #else
// 	# error Have to add to the B5M_INT16 type setting
// #endif  

/* defined (B5M_UINT16_TYPE) */
//#ifdef B5M_SIZEOF_SHORT == 2
	typedef unsigned short        B5M_UINT16;
// #elif B5M_SIZEOF_INT == 2
// 	typedef unsigned int          B5M_UINT16;
// #else
// 	# error Have to add to the B5M_UINT16 type setting
// #endif 

/* defined (B5M_INT32_TYPE) */
//#ifdef B5M_SIZEOF_INT == 4
	typedef int                   B5M_INT32;
// #elif B5M_SIZEOF_LONG == 4
// 	typedef long                  B5M_INT32;
// #else
// 	# error Have to add to the B5M_INT32 type setting
// #endif 

/* defined (B5M_UINT32_TYPE) */
//#ifdef B5M_SIZEOF_INT == 4
	typedef unsigned int          B5M_UINT32;
// #elif B5M_SIZEOF_LONG == 4
// 	typedef unsigned long         B5M_UINT32;
// #else
// 	# error Have to add to the B5M_UINT32 type setting
// #endif 

/* defined (B5M_INT64_TYPE) */
// #if defined (B5M_HAS_INT64_T)
// 	typedef int64_t               B5M_INT64;
// #elif B5M_SIZEOF_LONG == 8
// 	typedef long                  B5M_INT64;
// #elif B5M_SIZEOF_LONG_LONG == 8
	typedef long long             B5M_INT64;
//#endif 

// /* defined (B5M_UINT64_TYPE) */
// #if defined (B5M_HAS_UINT64_T)
// 	typedef uint64_t              B5M_UINT64;
// #elif B5M_SIZEOF_LONG == 8
// 	typedef unsigned long         B5M_UINT64;
// #elif B5M_SIZEOF_LONG_LONG == 8
	typedef unsigned long long    B5M_UINT64;
//#endif 

/// Define a generic byte for use in codecs
typedef B5M_UINT8 B5M_Byte;

// Define a pseudo wide character type when wchar is not supported so we
// can support basic wide character string operations.
#if defined (B5M_HAS_WCHAR)
	#  define B5M_WINT_T wint_t
	#  define B5M_WCHAR_T wchar_t
#else
	#  define B5M_WINT_T B5M_UINT16
	#  define B5M_WCHAR_T B5M_UINT16
#endif /* B5M_HAS_WCHAR */

#ifdef B5M_HAS_WCHAR
	typedef wchar_t B5M_TCHAR;
	typedef char B5M_ANTI_TCHAR;
#else /* B5M_USES_WCHAR */
	typedef char B5M_TCHAR;
#endif

// The number of bytes in a void *.
#ifndef B5M_SIZEOF_VOID_P
#  define B5M_SIZEOF_VOID_P B5M_SIZEOF_LONG
#endif /* B5M_SIZEOF_VOID_P */

B5M_END_VERSIONED_NAMESPACE_DECL

// Byte-order (endian-ness) determination.
// Byte swapping macros to deal with differences between little endian
// and big endian machines.  Note that "long" here refers to 32 bit
// quantities.
# define B5M_SWAP_LONG(L) ((B5M_SWAP_WORD ((L) & 0xFFFF) << 16) \
	| B5M_SWAP_WORD(((L) >> 16) & 0xFFFF))

# define B5M_SWAP_WORD(L) ((((L) & 0x00FF) << 8) | (((L) & 0xFF00) >> 8))

# define B5M_HTONL(X) htonl (X)
# define B5M_NTOHL(X) ntohl (X)

#define B5M_HTONS(x) htons(x)
#define B5M_NTOHS(x) ntohs(x)

// The number of bytes in a float.
# ifndef B5M_SIZEOF_FLOAT
#   if FLT_MAX_EXP == 128
#     define B5M_SIZEOF_FLOAT 4
#   elif FLT_MAX_EXP == 1024
#     define B5M_SIZEOF_FLOAT 8
#   else
#     error: unsupported float size, must be updated for this platform!
#   endif /* FLT_MAX_EXP */
# endif /* B5M_SIZEOF_FLOAT */

	// The number of bytes in a double.
# ifndef B5M_SIZEOF_DOUBLE
#   if DBL_MAX_EXP == 128
#     define B5M_SIZEOF_DOUBLE 4
#   elif DBL_MAX_EXP == 1024
#     define B5M_SIZEOF_DOUBLE 8
#   else
#     error: unsupported double size, must be updated for this platform!
#   endif /* DBL_MAX_EXP */
# endif /* B5M_SIZEOF_DOUBLE */

	// The number of bytes in a long double.
# ifndef B5M_SIZEOF_LONG_DOUBLE
#   if LDBL_MAX_EXP == 128
#     define B5M_SIZEOF_LONG_DOUBLE 4
#   elif LDBL_MAX_EXP == 1024
#     if defined (__powerpc64__)
#       define B5M_SIZEOF_LONG_DOUBLE 16
#     else
#       define B5M_SIZEOF_LONG_DOUBLE 8
#     endif
#   elif LDBL_MAX_EXP == 16384
#     if defined (LDBL_DIG)  &&  LDBL_DIG == 18
#       if defined (__ia64) || defined (__x86_64)
#         define B5M_SIZEOF_LONG_DOUBLE 16
#       else /* ! __ia64 || __x86_64 */
#         define B5M_SIZEOF_LONG_DOUBLE 12
#       endif /* __ia64 */
#     else  /* ! LDBL_DIG  ||  LDBL_DIG != 18 */
#       define B5M_SIZEOF_LONG_DOUBLE 16
#     endif /* ! LDBL_DIG  ||  LDBL_DIG != 18 */
#   else
#     error: unsupported double size, must be updated for this platform!
#   endif /* LDBL_MAX_EXP */
# endif /* B5M_SIZEOF_LONG_DOUBLE */

	// Max and min sizes for the ACE integer types.
#define B5M_CHAR_MAX 0x7F
#define B5M_CHAR_MIN -(B5M_CHAR_MAX)-1
#define B5M_OCTET_MAX 0xFF
#define B5M_INT16_MAX 0x7FFF
#define B5M_INT16_MIN -(B5M_INT16_MAX)-1
#define B5M_UINT16_MAX 0xFFFF
#define B5M_WCHAR_MAX B5M_UINT16_MAX
#define B5M_INT32_MAX 0x7FFFFFFF
#define B5M_INT32_MIN -(B5M_INT32_MAX)-1
#define B5M_UINT32_MAX 0xFFFFFFFF
#define B5M_INT64_MAX B5M_INT64_LITERAL(0x7FFFFFFFFFFFFFFF)
#define B5M_INT64_MIN -(B5M_INT64_MAX)-1
#define B5M_UINT64_MAX B5M_UINT64_LITERAL (0xFFFFFFFFFFFFFFFF)

	// These use ANSI/IEEE format.
#define B5M_FLT_MAX 3.402823466e+38F
#define B5M_FLT_MIN 1.175494351e-38F
#define B5M_DBL_MAX 1.7976931348623158e+308
#define B5M_DBL_MIN 2.2250738585072014e-308




//default constant 

# if !defined (B5M_UNIQUE_NAME_LEN)
#   define B5M_UNIQUE_NAME_LEN 100
# endif /* B5M_UNIQUE_NAME_LEN */


#if !defined (B5M_GUARD_ACTION)
#define B5M_GUARD_ACTION(MUTEX, OBJ, LOCK, ACTION, REACTION) \
	B5M_Guard< MUTEX > OBJ (LOCK); \
	if (OBJ.locked () != 0) { ACTION; } \
   else { REACTION; }
#endif /* !B5M_GUARD_ACTION */

#if !defined (B5M_GUARD_REACTION)
#define B5M_GUARD_REACTION(MUTEX, OBJ, LOCK, REACTION) \
	B5M_GUARD_ACTION(MUTEX, OBJ, LOCK, ;, REACTION)
#endif /* !B5M_GUARD_REACTION */

#if !defined (B5M_GUARD)
#define B5M_GUARD(MUTEX, OBJ, LOCK) \
	B5M_GUARD_REACTION(MUTEX, OBJ, LOCK, return)
#endif /* !B5M_GUARD */


#if !defined (B5M_GUARD_RETURN)
#define B5M_GUARD_RETURN(MUTEX, OBJ, LOCK, RETURN) \
	B5M_GUARD_REACTION(MUTEX, OBJ, LOCK, return RETURN)
#endif /* !B5M_GUARD_RETURN */


#define IS_VALID_STRING(X) ((X == NULL || wcslen(X) == 0) ? false : true)


#define B5M_NONE_COPYABLE(CLASS)     \
	private:\
	CLASS(const CLASS&);  \
	const CLASS& operator=(const CLASS&);\

#ifndef SAFE_RELEASE_POINTER
	#define SAFE_RELEASE_POINTER(p)		if (NULL != (p)) { delete (p); (p) = NULL;  }
#endif

#ifndef SAFE_RELEASE_ARRAY
	#define SAFE_RELEASE_ARRAY(p)		if (NULL != (p)) { delete[] (p); (p) = NULL; }
#endif

#ifndef SAFE_RELEASE_HANDLE
	#define SAFE_RELEASE_HANDLE(h) if (INVALID_HANDLE_VALUE != (h) || NULL != (h)) { CloseHandle((h)); h = NULL; }
#endif

//Assert.h
#if defined (B5M_DEBUG)
	#define B5M_ASSERT(X) assert(X)
#else
	#define B5M_ASSERT(x) \
		(static_cast<void>(0))
#endif /* B5M_DEBUG */



//Memory.h
#define B5M_bad_alloc /*::std::bad_alloc*/
#define B5M_nothrow   /*::std::notho*/
#define B5M_nothrow_t /*::std::nothrow_t*/

#define B5M_NEW_RETURN(POINTER,CONSTRUCTOR,RET_VAL) \
	do { POINTER = new CONSTRUCTOR; if (POINTER == 0) {return RET_VAL; } } while (0)

#define B5M_NEW(POINTER,CONSTRUCTOR) \
	do { POINTER = new CONSTRUCTOR; if (POINTER == 0) {return; } } while (0)

#define B5M_NEW_NORETURN(POINTER,CONSTRUCTOR) \
	do { POINTER = new CONSTRUCTOR; if (POINTER == 0) { } } while (0)

#endif